package de.dopichaj.labrador.index.backend;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.PriorityQueue;

import org.apache.log4j.Logger;

public final class MultiTermSearcher {
    
    private static final Logger log = Logger.getLogger(MultiTermSearcher.class);
    private final InvertedListSearcher searcher;
    
    public MultiTermSearcher(final InvertedListSearcher searcher) {
        this.searcher = searcher;
    }
    
    private static final class TFAndIterator implements Comparable<TFAndIterator> {
        private TermFrequency next;
        private final Iterator<TermFrequency> iterator;
        
        public TFAndIterator(final Iterator<TermFrequency> iterator,
            final TermFrequency next) {
            
            assert next != null;
            this.iterator = iterator;
            this.next = next;
        }
        
        public int getDocumentID() {
            return next.getDocumentID();
        }
        
        public int compareTo(TFAndIterator o) {
            
            if (getDocumentID() < o.getDocumentID()) {
                return -1;
            } else if (getDocumentID() > o.getDocumentID()) {
                return 1;
            } else {
                return next.compareTo(o.next);
            }
        }

        public void advance() {
            next = iterator.next();
        }
    }
    
    private static final class SearchIterator implements Iterator<List<TermFrequency>> {

        private final PriorityQueue<TFAndIterator> queue;
        
        public SearchIterator(final PriorityQueue<TFAndIterator> queue) {
            this.queue = queue;
        }
        
        public boolean hasNext() {
            return !queue.isEmpty();
        }

        public List<TermFrequency> next() {
            
            final List<TermFrequency> subList = new ArrayList<TermFrequency>();

            final int docID = queue.peek().getDocumentID();
            while (!queue.isEmpty() && queue.peek().getDocumentID() == docID) {
                final TFAndIterator current = queue.poll();
                subList.add(current.next);
                if (current.iterator.hasNext()) {
                    current.advance();
                    queue.add(current);
                }
            }
            
            return subList;
        }

        public void remove() {
            throw new UnsupportedOperationException();
        }
    }
    
    /**
     * Search for a collection of terms.
     * @return A list of lists of term frequencies; each sub-list is for one
     *    document.
     */
    public Iterator<List<TermFrequency>> search(final Collection<Term> terms)
        throws IOException {
        
        // de.dopichaj.labrador.search all sub-searchers
        final PriorityQueue<TFAndIterator> queue = new PriorityQueue<TFAndIterator>();
        for (final Term term : terms) {
            if (log.isDebugEnabled()) {
                log.debug("Searching for " + term);
            }
            final Iterator<TermFrequency> it = searcher.search(term);
            if (it.hasNext()) {
                queue.add(new TFAndIterator(it, it.next()));
            }
        }

        return new SearchIterator(queue);
    }
}
/*
Copyright (c) 2007 Philipp Dopichaj

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/